package com.nehc.nettyserver.service.impl;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import com.nehc.nettyserver.service.CacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 基于Caffeine的缓存服务实现
 * 
 * @author NEHC
 */
@Service
@Slf4j
public class CaffeineServiceImpl implements CacheService {
    
    /**
     * 缓存管理器
     */
    private final Map<CacheType, Cache<String, Object>> caches = new ConcurrentHashMap<>();
    
    /**
     * 构造函数，初始化缓存
     */
    public CaffeineServiceImpl() {
        // 连接缓存 - 1小时过期，最大10000个
        caches.put(CacheType.CONNECTION, Caffeine.newBuilder()
                .expireAfterAccess(1, TimeUnit.HOURS)
                .maximumSize(10000)
                .recordStats()
                .build());
        
        // 消息缓存 - 1天过期，最大100000个
        caches.put(CacheType.MESSAGE, Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.DAYS)
                .maximumSize(100000)
                .recordStats()
                .build());
        
        // 用户缓存 - 1小时过期，最大10000个
        caches.put(CacheType.USER, Caffeine.newBuilder()
                .expireAfterAccess(1, TimeUnit.HOURS)
                .maximumSize(10000)
                .recordStats()
                .build());
        
        // 统计缓存 - 5分钟过期，最大1000个
        caches.put(CacheType.STATS, Caffeine.newBuilder()
                .expireAfterWrite(5, TimeUnit.MINUTES)
                .maximumSize(1000)
                .recordStats()
                .build());
        
        // 配置缓存 - 永不过期，最大100个
        caches.put(CacheType.CONFIG, Caffeine.newBuilder()
                .maximumSize(100)
                .recordStats()
                .build());
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public <T> T get(CacheType cacheType, String key) {
        try {
            Cache<String, Object> cache = caches.get(cacheType);
            return (T) cache.getIfPresent(key);
        } catch (Exception e) {
            log.error("Failed to get from cache: {}", e.getMessage());
            return null;
        }
    }
    
    @Override
    public <T> void put(CacheType cacheType, String key, T value) {
        try {
            Cache<String, Object> cache = caches.get(cacheType);
            cache.put(key, value);
        } catch (Exception e) {
            log.error("Failed to put to cache: {}", e.getMessage());
        }
    }
    
    @Override
    public <T> void put(CacheType cacheType, String key, T value, long expireSeconds) {
        try {
            // Caffeine不直接支持单独设置过期时间，这里使用默认过期策略
            Cache<String, Object> cache = caches.get(cacheType);
            cache.put(key, value);
            
            // 可以通过额外的Map记录过期时间，并在get时检查，但这里简化处理
        } catch (Exception e) {
            log.error("Failed to put to cache with expiration: {}", e.getMessage());
        }
    }
    
    @Override
    public void remove(CacheType cacheType, String key) {
        try {
            Cache<String, Object> cache = caches.get(cacheType);
            cache.invalidate(key);
        } catch (Exception e) {
            log.error("Failed to remove from cache: {}", e.getMessage());
        }
    }
    
    @Override
    public boolean exists(CacheType cacheType, String key) {
        try {
            Cache<String, Object> cache = caches.get(cacheType);
            return cache.getIfPresent(key) != null;
        } catch (Exception e) {
            log.error("Failed to check existence in cache: {}", e.getMessage());
            return false;
        }
    }
    
    @Override
    public Set<String> keys(CacheType cacheType) {
        try {
            Cache<String, Object> cache = caches.get(cacheType);
            return cache.asMap().keySet();
        } catch (Exception e) {
            log.error("Failed to get keys from cache: {}", e.getMessage());
            return Set.of();
        }
    }
    
    @Override
    public Set<String> keys(CacheType cacheType, String prefix) {
        try {
            Cache<String, Object> cache = caches.get(cacheType);
            return cache.asMap().keySet().stream()
                    .filter(key -> key.startsWith(prefix))
                    .collect(Collectors.toSet());
        } catch (Exception e) {
            log.error("Failed to get keys with prefix from cache: {}", e.getMessage());
            return Set.of();
        }
    }
    
    @Override
    public void clear(CacheType cacheType) {
        try {
            Cache<String, Object> cache = caches.get(cacheType);
            cache.invalidateAll();
        } catch (Exception e) {
            log.error("Failed to clear cache: {}", e.getMessage());
        }
    }
    
    @Override
    public Map<String, Object> getStats() {
        Map<String, Object> stats = new HashMap<>();
        
        for (Map.Entry<CacheType, Cache<String, Object>> entry : caches.entrySet()) {
            CacheType cacheType = entry.getKey();
            Cache<String, Object> cache = entry.getValue();
            
            CacheStats cacheStats = cache.stats();
            Map<String, Object> typeStat = new HashMap<>();
            typeStat.put("size", cache.estimatedSize());
            typeStat.put("hitRate", cacheStats.hitRate());
            typeStat.put("hitCount", cacheStats.hitCount());
            typeStat.put("missCount", cacheStats.missCount());
            typeStat.put("evictionCount", cacheStats.evictionCount());
            
            stats.put(cacheType.name(), typeStat);
        }
        
        return stats;
    }
} 